package com.jzr.bedside.api

import android.annotation.SuppressLint
import com.blankj.utilcode.utils.LogUtils
import com.blankj.utilcode.utils.NetworkUtils
import com.jzr.bedside.api.persistentcookiejar.PersistentCookieJar
import com.jzr.bedside.base.BaseApplication
import com.jzr.bedside.utils.CommonUtil
import okhttp3.*
import okio.Buffer
import java.io.File
import java.io.IOException
import java.nio.charset.Charset
import java.util.concurrent.TimeUnit
import com.jzr.bedside.api.Okhttp.MoreBaseUrlInterceptor as MoreBaseUrlInterceptor



internal object Okhttp {
    private var cookieJar: PersistentCookieJar? = null
    fun provideOkHttpClient(): OkHttpClient {

        //cookie
//        cookieJar = PersistentCookieJar(
//            SetCookieCache(), SharedPrefsCookiePersistor(
//                BaseApplication.getContext()
//            )
//        );

        val httpCacheDir = File(BaseApplication.getContext()?.cacheDir, "response");
        val cacheSize = 10 * 1024 * 1024 //10 MiB
        val cache = Cache(httpCacheDir, cacheSize.toLong())
        val builder =
            OkHttpClient.Builder().connectTimeout(10, TimeUnit.SECONDS)
                .connectTimeout(20 * 1000.toLong(), TimeUnit.MILLISECONDS)
                .readTimeout(20 * 1000.toLong(), TimeUnit.MILLISECONDS)
                .addInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)
                .addInterceptor(mHeaderInterceptor) //添加头部信息拦截器
                .addInterceptor(LoggingInterceptor())
                .retryOnConnectionFailure(true) // 失败重发
                .cache(cache)
//                .cookieJar(cookieJar)
//                .addInterceptor(new TokenInterceptor())
                //处理多BaseUrl,添加应用拦截器
                .addInterceptor(MoreBaseUrlInterceptor)
        return builder.build()
    }

    private val REWRITE_CACHE_CONTROL_INTERCEPTOR: Interceptor =
        Interceptor { chain ->
            val cacheBuilder = CacheControl.Builder()
            cacheBuilder.maxAge(0, TimeUnit.SECONDS)
            cacheBuilder.maxStale(365, TimeUnit.DAYS)
            val cacheControl = cacheBuilder.build()
            var request = chain.request()
            if (!NetworkUtils.isAvailableByPing()) {
                request = request.newBuilder()
                    .cacheControl(cacheControl)
                    .build()
            }
            val originalResponse = chain.proceed(request)
            if (NetworkUtils.isAvailableByPing()) {
                val maxAge = 0 //read from cache
                originalResponse.newBuilder()
                    .removeHeader("Pragma")
                    .header("Cache-Control", "public ,max-age=$maxAge")
                    .build()
            } else {
                val maxStale = 60 * 60 * 24 * 28 //tolerate 4-weeks stale
                originalResponse.newBuilder()
                    .removeHeader("Prama")
                    .header("Cache-Control", "poublic, only-if-cached, max-stale=$maxStale")
                    .build()
            }
        }

    fun transMapToString(map: Map<*, *>): String {
        var entry: Map.Entry<*, *>
        val sb = StringBuilder()
        val iterator: Iterator<*> = map.entries.iterator()
        while (iterator.hasNext()) {
            entry = iterator.next() as Map.Entry<*, *>
            sb.append(entry.key.toString()).append(" == ")
                .append(if (null == entry.value) "" else entry.value.toString())
                .append(if (iterator.hasNext()) "\n" else "")
        }
        return sb.toString()
    }

    fun formatJson(jsonStr: String?): String {
        if (null == jsonStr || "" == jsonStr) {
            return ""
        }
        val sb = StringBuilder()
        var last = '\u0000'
        var current = '\u0000'
        var indent = 0
        for (i in 0 until jsonStr.length) {
            last = current
            current = jsonStr[i]
            when (current) {
                '{', '[' -> {
                    sb.append(current)
                    sb.append('\n')
                    indent++
                    addIndentBlank(sb, indent)
                }
                '}', ']' -> {
                    sb.append('\n')
                    indent--
                    addIndentBlank(sb, indent)
                    sb.append(current)
                }
                ',' -> {
                    sb.append(current)
                    if (last != '\\') {
                        sb.append('\n')
                        addIndentBlank(sb, indent)
                    }
                }
                else -> sb.append(current)
            }
        }
        return sb.toString()
    }

    private fun addIndentBlank(sb: StringBuilder, indent: Int) {
        for (i in 0 until indent) {
            sb.append('\t')
        }
    }

    /**增加头部信息的拦截器 */
    private var mHeaderInterceptor =
        Interceptor { chain: Interceptor.Chain ->
            val builder = chain.request().newBuilder()
            builder.addHeader(
                "User-Agent",
                "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.108 Safari/537.36 2345Explorer/8.0.0.13547"
            )
            builder.addHeader("Cache-Control", "max-age=0")
            builder.addHeader("Upgrade-Insecure-Requests", "1")
            builder.addHeader("X-Requested-With", "XMLHttpRequest")
            builder.addHeader(
                "Cookie",
                "uuid=\"w:f2e0e469165542f8a3960f67cb354026\"; __tasessionId=4p6q77g6q1479458262778; csrftoken=7de2dd812d513441f85cf8272f015ce5; tt_webid=36385357187"
            )
            builder.addHeader("X-Access-Token", "BS919 293DCFC6BB2ED176140B91CB267C9442")
            chain.proceed(builder.build())
        }

   private  var  MoreBaseUrlInterceptor: Interceptor =
       Interceptor { chain -> //获取原始的originalRequest
           val originalRequest = chain.request()
           //获取老的url
           val oldUrl = originalRequest.url()
           //获取originalRequest的创建者builder
           val builder = originalRequest.newBuilder()
           val baseURL: HttpUrl = HttpUrl.parse(CommonUtil.getBaseUrl())
           //重建新的HttpUrl，需要重新设置的url部分
           val newHttpUrl = oldUrl.newBuilder()
               .scheme(baseURL.scheme())
               .host(baseURL.host())
               .port(baseURL.port())
               .build()

           //获取处理后的新newRequest
           val newRequest =
               builder.url(newHttpUrl)
                   .build()
           chain.proceed(newRequest)
       }


    internal class LoggingInterceptor : Interceptor {
        @SuppressLint("DefaultLocale")
        @Throws(IOException::class)
        override fun intercept(chain: Interceptor.Chain): Response {
            val UTF8 = Charset.forName("UTF-8")
            val request = chain.request()
            val t1 = System.nanoTime() //请求发起的时间
            val map: MutableMap<String, String?> =
                HashMap()
            for (i in request.url().queryParameterNames().indices) {
                map[request.url().queryParameterName(i)] = request.url().queryParameterValue(i)
            }
            val response = chain.proceed(request)
            val t2 = System.nanoTime() //收到响应的时间
            val responseBody = response.peekBody(1024 * 1024.toLong())

            val requestBody = request.body()
            var body: String? = null
            if (requestBody != null) {
                val buffer = Buffer()
                requestBody.writeTo(buffer)
                var charset: Charset = UTF8
                val contentType: MediaType? = requestBody.contentType()
                if (contentType != null) {
                    charset = contentType.charset(UTF8)!!
                }
                body = buffer.readString(charset)
            }

            LogUtils.e(
                String.format(
                    "接收响应: [%s] %n返回json:【%s】%n请求参数: [%s] %n请求body: [%s] %n响应时间[%.1fms]",
                    response.request().url(),
                    formatJson(responseBody.string()),
                    transMapToString(map),
                    body,
                    (t2 - t1) / 1e6
                )
            )
            return response
        }
    }
}